﻿using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Animation;

namespace MyOS.UserControls
{
    public class NavigationPanel : StackPanel
    {
        private static double _countOfPage;


        private static readonly TimeSpan Duration = TimeSpan.FromMilliseconds(250);
        private readonly TranslateTransform _navigationPanelTranslateTransform;

        public NavigationPanel()
        {
            Orientation = Orientation.Horizontal;


            _navigationPanelTranslateTransform = new TranslateTransform();

            Loaded += NavigationPanel_Loaded;
        }

        public event EventHandler AnimationComplete;

        private void NavigationPanel_Loaded(object sender, RoutedEventArgs e)
        {
            _countOfPage = Children.Count;
            CurrentIndex = 0;
            foreach (FrameworkElement fe in Children) fe.RenderTransform = _navigationPanelTranslateTransform;
        }

        public void Next()
        {
            AnimationChildren(true);
        }

        public void Previous()
        {
            AnimationChildren(false);
        }


        private bool ValidateNext()
        {
            return CurrentIndex < _countOfPage - 1 && CurrentIndex >= 0;
        }


        private bool ValidatePrevious()
        {
            return CurrentIndex <= _countOfPage - 1 && CurrentIndex > 0;
        }

        private bool ValidateCurrentIndex()
        {
            return CurrentIndex > -1 && CurrentIndex < Children.Count;
        }

        private void AnimationChildren(bool forward)
        {
            var currentTranX = _navigationPanelTranslateTransform.X;
            var nextTranX = currentTranX;
            if (forward)
            {
                if (ValidateCurrentIndex()) nextTranX -= ((FrameworkElement) Children[CurrentIndex]).ActualWidth;
            }
            else
            {
                if (ValidateCurrentIndex()) nextTranX += ((FrameworkElement) Children[CurrentIndex]).ActualWidth;
            }

            var da = new DoubleAnimation(currentTranX, nextTranX, Duration);
            da.Completed += (o1, e1) =>
            {
                CurrentIndex += forward ? 1 : -1;
                AnimationComplete?.Invoke(this, e1);
            };

            _navigationPanelTranslateTransform.BeginAnimation(TranslateTransform.XProperty, da);
        }

        #region CurrentIndex

        /// <summary>
        ///     The <see cref="CurrentIndex" /> dependency property's name.
        /// </summary>
        public const string CurrentIndexPropertyName = "CurrentIndex";

        /// <summary>
        ///     Gets or sets the value of the <see cref="CurrentIndex" />
        ///     property. This is a dependency property.
        /// </summary>
        public int CurrentIndex
        {
            get => (int) GetValue(CurrentIndexProperty);
            set => SetValue(CurrentIndexProperty, value);
        }

        /// <summary>
        ///     Identifies the <see cref="CurrentIndex" /> dependency property.
        /// </summary>
        public static readonly DependencyProperty CurrentIndexProperty = DependencyProperty.Register(
            CurrentIndexPropertyName,
            typeof(int),
            typeof(NavigationPanel),
            new UIPropertyMetadata(-1, OnCurrentIndexChanged));

        private static void OnCurrentIndexChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            (d as NavigationPanel)?.OnCurrentIndexChanged((int) e.OldValue, (int) e.NewValue);
        }

        protected virtual void OnCurrentIndexChanged(int oldIndex, int newIndex)
        {
            NextIsValid = ValidateNext();
            PreviousIsValid = ValidatePrevious();
        }

        #endregion // CurrentIndex  


        #region NextIsValid

        /// <summary>
        ///     The <see cref="NextIsValid" /> dependency property's name.
        /// </summary>
        public const string NextIsValidPropertyName = "NextIsValid";

        /// <summary>
        ///     Gets or sets the value of the <see cref="NextIsValid" />
        ///     property. This is a dependency property.
        /// </summary>
        public bool NextIsValid
        {
            get => (bool) GetValue(NextIsValidProperty);
            set => SetValue(NextIsValidProperty, value);
        }

        /// <summary>
        ///     Identifies the <see cref="NextIsValid" /> dependency property.
        /// </summary>
        public static readonly DependencyProperty NextIsValidProperty = DependencyProperty.Register(
            NextIsValidPropertyName,
            typeof(bool),
            typeof(NavigationPanel),
            new UIPropertyMetadata(false));

        #endregion // NextIsValid  

        #region PreviousIsValid

        /// <summary>
        ///     The <see cref="PreviousIsValid" /> dependency property's name.
        /// </summary>
        public const string PreviousIsValidPropertyName = "PreviousIsValid";

        /// <summary>
        ///     Gets or sets the value of the <see cref="PreviousIsValid" />
        ///     property. This is a dependency property.
        /// </summary>
        public bool PreviousIsValid
        {
            get => (bool) GetValue(PreviousIsValidProperty);
            set => SetValue(PreviousIsValidProperty, value);
        }

        /// <summary>
        ///     Identifies the <see cref="PreviousIsValid" /> dependency property.
        /// </summary>
        public static readonly DependencyProperty PreviousIsValidProperty = DependencyProperty.Register(
            PreviousIsValidPropertyName,
            typeof(bool),
            typeof(NavigationPanel),
            new UIPropertyMetadata(false));

        #endregion // PreviousIsValid  
    }
}